
using System;
using System.Text;
using GeoFramework;

namespace GeoFramework.Gps.Nmea
{
	/// <summary>
	/// Magellan devices only.  Represents a sentence containing fix status and remaining battery life.
	/// </summary>
    public class PmgnstSentence : NmeaSentence
	{
		double pVersionNumber;
		FixMethod pFixMethod;
		bool pIsFixed;
		int pNumbersChange1;
		TimeSpan pRemainingBatteryLife;
		int pNumbersChange2;
		int pCurrentPseudorandomNumber;

		#region Constructors

		public PmgnstSentence(string sentence) : base(sentence)
		{
			// Is the checksum valid?
			if (!IsValid && !IsPartialSentenceParsingAllowed)
			{
				pFixMethod = FixMethod.NoFix;
				pIsFixed = false;
				pRemainingBatteryLife = TimeSpan.Zero;
				// No.  Do no parsing
				return;
			}

			// Magellan-only sentence:
			//  $PMGNST,02.12,3,T,534,05.0,+03327,00*40 

			// where:
			//	  02.12   Version number?
			//	  3	   2D or 3D
			//	  T	   True if we have a fix False otherwise
			//			 534:		 numbers(change - unknown)
			//	  05.0	time left on the GPS battery in hours
			//	  +03327  numbers change (freq. compensation?)
			//	  00	  PRN number receiving current focus
			//	  *40	 checksum

			// This is a custom Magellan  Set the manufacturer
			//Receiver.Device.SetManufacturer(Manufacturer.Magellan);

			try
			{
				// Get the version number
				if(WordCount > 1 && Words[1].Length != 0)
						pVersionNumber = double.Parse(Words[1], NmeaCultureInfo);
				else
					pVersionNumber = 0;

				// Set whether the device is in 2-D or 3-D mode
				if(WordCount > 2)
				{
					switch (Words[2])
					{
						case "2":
							pFixMethod = FixMethod.Fix2D;
							break;
						case "3":
							pFixMethod = FixMethod.Fix3D;
							break;
					}
				}
				else
				{
					pFixMethod = FixMethod.NoFix;
				}

				// Set whether or not the device has a fix
				if(WordCount > 3)
				{
					switch (Words[3])
					{
						case "t":
						case "T":
							pIsFixed = true;
							break;
						case "f":
						case "F":
							pIsFixed = false;
							break;
					}
				}
				else
				{
					pIsFixed = false;
				}

				if(WordCount > 4 && Words[4].Length != 0)
						pNumbersChange1 = int.Parse(Words[4], NmeaCultureInfo);
				else
					pNumbersChange1 = 0;

				if(WordCount > 5 && Words[5].Length != 0)
				{
					double RawTime = double.Parse(Words[5], NmeaCultureInfo);
					int Hours = Convert.ToInt32(Math.Floor(RawTime).ToString(NmeaCultureInfo), NmeaCultureInfo);
					RawTime = RawTime - Hours;
					RawTime = RawTime * 60;
					int Minutes = Convert.ToInt32(Math.Floor(RawTime).ToString(NmeaCultureInfo), NmeaCultureInfo);
					RawTime = RawTime - Minutes;
					RawTime = RawTime * 60;
					int Seconds = Convert.ToInt32(Math.Floor(RawTime).ToString(NmeaCultureInfo), NmeaCultureInfo);
					// Now create the battery life as a time span
					pRemainingBatteryLife = new TimeSpan(Hours, Minutes, Seconds);
				}
				else
				{
					pRemainingBatteryLife = TimeSpan.Zero;
				}

				if(WordCount > 6 && Words[6].Length != 0)
						pNumbersChange2 = int.Parse(Words[6], NmeaCultureInfo);
				else
					pNumbersChange2 = 0;

				if(WordCount > 7 && Words[7].Length != 0)
						pCurrentPseudorandomNumber = int.Parse(Words[7], NmeaCultureInfo);
				else
					pCurrentPseudorandomNumber = 0;
			}
			catch(Exception ex)
			{
				throw new NmeaSentenceException(this, "A $PMGNST sentence contained unrecognizable data.", ex);
			}
		}


		public PmgnstSentence(byte[] bytes) 
            : this(ASCIIEncoding.ASCII.GetString(bytes, 0, bytes.Length))
		{}

		public PmgnstSentence(int versionNumber, FixMethod fixMethod, bool isFixed, int numbersChange1,
			TimeSpan remainingBatteryLife, int numbersChange2, int currentPseudorandomNumber)
		{
			// Store all variables
			pVersionNumber = versionNumber;
			pFixMethod = fixMethod;
			pIsFixed = isFixed;
			pNumbersChange1 = numbersChange1;
			pRemainingBatteryLife = remainingBatteryLife;
			pNumbersChange2 = numbersChange2;
			pCurrentPseudorandomNumber = currentPseudorandomNumber;
			// Output the information as a PMGNST sentence (!!)
			StringBuilder Sentence = new StringBuilder();
			Sentence.Append("$PMGNST,");
			// Write the version number
			Sentence.Append(VersionNumber.ToString(NmeaCultureInfo));
			Sentence.Append(",");
			// Write the fix method
			switch(FixMethod)
			{
				case FixMethod.NoFix:
					Sentence.Append("0");
					break;
				case FixMethod.Fix2D:
					Sentence.Append("2");
					break;
				case FixMethod.Fix3D:
					Sentence.Append("3");
					break;
				default:
					Sentence.Append("0");
					break;
			}
			Sentence.Append(",");
			// Write fix status
			if(IsFixed)
				Sentence.Append("T");
			else
				Sentence.Append("F");
			Sentence.Append(",");
			// Write numbers change 1
			Sentence.Append(NumbersChange1.ToString(NmeaCultureInfo).PadLeft(3, '0'));
			Sentence.Append(",");
			// Write remaining battery life in fractional hours
			Sentence.Append(RemainingBatteryLife.TotalHours.ToString("#.#", NmeaCultureInfo));
			Sentence.Append(",+");
			// Write numbers change #2
			Sentence.Append(NumbersChange2.ToString(NmeaCultureInfo).PadLeft(5, '0'));
			// Set the sentence
			SetSentence(Sentence.ToString());
			SetChecksum();
		}
		#endregion

		#region Public Members

		public double VersionNumber
		{
			get
			{
				return pVersionNumber;
			}
		}

		public FixMethod FixMethod
		{
			get
			{
				return pFixMethod;
			}
		}

		public bool IsFixed
		{
			get
			{
				return pIsFixed;
			}
		}

		public int NumbersChange1
		{
			get
			{
				return pNumbersChange1;
			}
		}

		public TimeSpan RemainingBatteryLife
		{
			get
			{
				return pRemainingBatteryLife;
			}
		}

		public int NumbersChange2
		{
			get
			{
				return pNumbersChange2;
			}
		}

		public int CurrentPseudorandomNumber
		{
			get
			{
				return pCurrentPseudorandomNumber;
			}
		}

		/// <summary>
		/// Indicates that this sentence is supported by GPS.NET.
		/// </summary>
		public override bool IsSupported
		{
			get
			{
				return true;
			}
		}

		#endregion

		public static PmgnstSentence Parse(string sentence)
		{
			return new PmgnstSentence(sentence);
		}
	}
}
